package com.github.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.*;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.github.config.WebServerProperties;
import com.github.core.parse.spel.SpelParser;
import com.github.core.parse.sse.ChatResponse;
import com.github.core.parse.sse.LlmParser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.util.*;


/**
 * @author 陈敏
 * @version IndexController.java, v 1.1 2021/5/25 9:45 chenmin Exp $
 * Created on 2021/5/25
 *
 */
@Slf4j
@RestController
@RequestMapping("/index")
public class IndexController {

    @Autowired
    private WebServerProperties webServerProperties;
    @Autowired
    private SpelParser spelParser;

    @RequestMapping("/{method}/**")
    public Flux<ServerSentEvent<ChatResponse>> index(@PathVariable("method") String method,
                                                     HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        JSONObject spelParam = new JSONObject();
        String requestMethod = request.getMethod().toUpperCase();
        Map<String, String> paramMap = ServletUtil.getParamMap(request);
        if (ObjectUtil.isNotEmpty(paramMap)) {
            String urlParam = HttpUtil.toParams(paramMap);
            spelParam.set("URL_PARAM", urlParam);
            log.info("请求方法: " + method + "?" + urlParam);
        } else {
            log.info("请求方法: " + method);
        }
        Map<String, String> headerMap = ServletUtil.getHeaderMap(request);
        if (ObjectUtil.isNotEmpty(headerMap)) {
            JSONObject headerObject = new JSONObject(headerMap);
            spelParam.set("HEADER", headerObject);
            log.info("请求头为: \n" + headerObject.toStringPretty());
        }
        String body = ServletUtil.getBody(request);
        JSONObject bodyJson =new JSONObject();
        if (ObjectUtil.isNotEmpty(body)) {
            bodyJson = JSONUtil.parseObj(body);
            spelParam.set("REQ_BODY", bodyJson);
            log.info("请求体为: \n" + bodyJson.toStringPretty());
        }
        JSONObject dbJSON = getJSONDB();
        Object result = JSONUtil.getByPath(dbJSON, requestMethod + StrUtil.DOT + method + StrUtil.DOT + "data");
        if (ObjectUtil.isEmpty(result)) {
            response.getWriter().write("No Data");
            return null;
        }
        JSONObject resultObj = JSONUtil.parseObj(result);
        Object infoObj = JSONUtil.getByPath(dbJSON, requestMethod + StrUtil.DOT + method + StrUtil.DOT + "info");
        if (ObjectUtil.isNotEmpty(infoObj)) {
            JSONObject info = JSONUtil.parseObj(infoObj);
            if (info.containsKey("delay_time")) {
                Long delay_time = info.getLong("delay_time", 0L);
                Thread.sleep(delay_time);
            }
            if (info.containsKey("spel")) {
                Boolean spel = info.getBool("spel", Boolean.FALSE);
                if (spel) {
                    resultObj = JSONUtil.parseObj(spelParser.parse(resultObj.toString(), spelParam));
                }
            }
            if (info.containsKey("streamField")) {
                Boolean stream = bodyJson.getBool("stream",Boolean.FALSE);
                List<ChatResponse> collect = LlmParser.parse(resultObj,stream,info.getStr("streamField"),info.getInt("streamStep",2));
                if (stream) {
                    // 设置正确的响应头以支持 SSE
                    response.setHeader("Content-Type", MediaType.TEXT_EVENT_STREAM_VALUE);
                    // 将内容分解为单个字符的 ChatResponse 列表

                    return Flux.interval(Duration.ofMillis(200))  // 时间间隔调整为300ms
                            .take(collect.size())
                            .map(sequence -> {
                                ChatResponse chatResponse = collect.get(sequence.intValue());
                                return ServerSentEvent.<ChatResponse>builder()
                                        .data(chatResponse)
                                        .build();
                            })
                            .doOnError(e -> log.error("Error in SSE stream: ", e));
                } else {
                    // 不流式返回时，直接返回单个信息
                    // 单次返回事件
                    response.getWriter().write(JSONUtil.toJsonPrettyStr(collect.get(0)));
                    return null;
                }
            }
        }
        log.info("响应数据为: \n" + resultObj.toStringPretty());
        response.getWriter().write(resultObj.toStringPretty());
        return null;
    }

    @GetMapping("/allMethods")
    public Object getAllMethods() {
        JSONObject dbJSON = getJSONDB();
        JSONObject jsonMethod = new JSONObject();
        dbJSON.forEach((requestMethod, methods) -> jsonMethod.set(requestMethod, JSONUtil.parseObj(methods).keySet()));
        return jsonMethod;
    }

    @GetMapping("/db")
    public Object getDB(@RequestParam String requestMethod, @RequestParam String method) {
        JSONObject jsondb = getJSONDB();
        if (ObjectUtil.isNotEmpty(requestMethod) && ObjectUtil.isNotEmpty(method)) {
            return jsondb.getByPath(requestMethod + StrUtil.DOT + method);
        }
        return jsondb;
    }

    @PutMapping("/addMethod/{requestMethod}/{method}")
    public Object addMethod(@PathVariable("requestMethod") String requestMethod,
                            @PathVariable("method") String method, @RequestBody JSONObject body) throws IOException {
        JSONObject jsondb = getJSONDB();
        String jsonPath = webServerProperties.getJsonPath();
        Object oldValue = jsondb.getByPath(requestMethod + StrUtil.DOT + method);
        if (ObjectUtil.isNotEmpty(oldValue)) {
            String historyFilePath = jsonPath.replace(new File(jsonPath).getName(), "") + StrUtil.SLASH + method + StrUtil.UNDERLINE + requestMethod + ".json";
            File historyFile = new File(historyFilePath);
            JSONObject history = new JSONObject();
            if (historyFile.exists()) {
                history.putAll(JSONUtil.readJSONObject(historyFile, CharsetUtil.CHARSET_UTF_8));
            } else {
                historyFile.createNewFile();
            }
            history.set(DateUtil.now(), body);
            FileUtil.writeUtf8String(history.toString(), historyFile);
        }
        JSONUtil.putByPath(jsondb, requestMethod + StrUtil.DOT + method, body);
        FileUtil.writeUtf8String(jsondb.toString(), jsonPath);
        return "OK";
    }

    @DeleteMapping("/deleteMethod/{requestMethod}/{method}")
    public Object deleteMethod(@PathVariable("requestMethod") String requestMethod, @PathVariable("method") String method) {
        JSONObject jsondb = getJSONDB();
        JSONObject jsonObject = jsondb.getJSONObject(requestMethod);
        jsonObject.remove(method);
        jsondb.putOpt(requestMethod, jsonObject);
        String jsonPath = webServerProperties.getJsonPath();
        FileUtil.writeUtf8String(jsondb.toString(), jsonPath);
        return "OK";
    }

    private JSONObject getJSONDB() {
        String jsonPath = webServerProperties.getJsonPath();
        if (!FileUtil.exist(jsonPath)) {
            FileUtil.writeUtf8String("{}", jsonPath);
        }
        return JSONUtil.readJSONObject(new File(jsonPath), CharsetUtil.CHARSET_UTF_8);
    }

}


